import { fabric } from 'fabric';
import { throttle } from 'lodash-es';
import { BasePalette } from './BasePalette';
import {
  AUTO_MINUS_ICON,
  AUTO_SELECT_ACON,
  BRUSH_ICON,
  ERASER_ICON,
} from './constants/markTool.constant';
import type { IBasePaletteOption, TPathData } from './types/BasePalette.type';
import { ECursorType, EMarkTool } from './types/BasePalette.type';
import type { IPreSegInfo, ISegMaskInfo2 } from './types/DrawPalette.type';

import {
  HOVER_MASK_COLOR,
  HOVER_NEGATIVE_MASK_COLOR,
  MASK_BLACK_TRANSPARENT_COLOR,
  MASK_COLOR,
} from './constants/mask.constant';
import { PRISEGINFOS } from './mockData/preSegInfos';
import {
  checkoutIsOutArea,
  getLocation,
  getPixelIndexByCoord,
  scaleToFitMaxDimension,
  transPreSegInfoFormat,
} from './tools/canvas.tool';
import { pictureLoader } from './tools/pictureLoader.tool';

const DEFAULT_VIEW_PORT_TRANSFORM = [1, 0, 0, 1, 0, 0];

export class DrawPalette extends BasePalette {
  // *** 图像相关 ***
  protected pictureEl!: HTMLImageElement | null;
  protected pictureFabricImage!: fabric.Image | null;
  protected pictureWidth = 0;
  protected pictureHeight = 0;
  pictureScale = 0; // 图像缩放比例

  markTool: EMarkTool | null = EMarkTool.AUTO_SELECT; // 选中标注工具
  strokeWidth = 50; // 画笔宽度
  strokeColor = '#000000'; // 画笔颜色
  private toolCursor: fabric.Object | null = null; //自定义鼠标光标 fabric.Image

  private readonly version: number = 0;
  // 预分割信息
  private preSegInfos = new Map<number, IPreSegInfo>();

  // ***  *** 绘制相关 ***
  private movePreviewMask: {
    index: number;
    fabricObj: fabric.Image | fabric.Path;
    pathData?: TPathData[];
  } | null = null; // 鼠标hover过程中预览mask

  // 图像分割mask(mouseup时候拼接)
  private segmentationMask: ISegMaskInfo2 | null = null;

  private isMarking: boolean = false;

  constructor(option: IBasePaletteOption) {
    super(option);
    const { wrapper, defaultMarkTool, defaultStrokeWidth, defaultStrokeColor } =
      option;
    if (!wrapper) {
      throw new Error(
        'sorry you must provide an HTMLDivElement as this wrapper container',
      );
    }
    //设置默认标注工具
    if (defaultMarkTool) {
      this.markTool = defaultMarkTool;
    }
    // 设置默认画笔笔触宽度
    if (defaultStrokeWidth) {
      this.strokeWidth = defaultStrokeWidth;
    }
    // 设置默认画笔笔触颜色
    if (defaultStrokeColor) {
      this.strokeColor = defaultStrokeColor;
    }
    // 添加事件监听器
    this.addEventListener();
    // this.emit('plateInit', this);
  }

  /**
   * @description 获取场景初始比例： 图片如何等比缩放才能使得整个图能在canvas容器中不被裁剪不变形展示(contain) pictureWidth * x = canvasWidth 或者 pictureHeight * x = canvasHeight
   * @returns {void}
   */
  get getStartZoom(): number {
    let startZoom = 1;
    const { sceneWidth, sceneHeight } = this; // 场景尺寸  960   540
    const { pictureWidth, pictureHeight } = this; // 图像尺寸 960 960
    if (!pictureWidth || !pictureHeight || !sceneWidth) return 1;
    if (pictureWidth > pictureHeight) {
      startZoom = Number(sceneWidth / pictureWidth);
    } else {
      startZoom = Number(sceneHeight / pictureHeight);
    }
    this.minZoomFactor = Math.min(this.minZoomFactor, startZoom / 2);
    return startZoom;
  }

  /**
   * @description 场景居中缩放、
   * <p>[4]: 水平移动（x 轴方向） [5]: 垂直移动（y 轴方向）</p>
      <p>[1]: 水平选择（x 轴方向）[2]: 垂直旋转（y 轴方向）</p>
      <p>[0]: 水平缩放（x 轴方向）[3]: 垂直缩放（y 轴方向）</p>
   * @param {}
   * @returns {}
   */
  protected sceneToCenter(): void {
    const { sceneWidth, sceneHeight } = this;
    // 计算平移相对位置中心点
    const offsetX = Number((sceneWidth - this.pictureWidth * this.zoom) / 2);
    const offsetY = Number((sceneHeight - this.pictureHeight * this.zoom) / 2);
    // console.log('--offsetX---offsetY---:', offsetX, offsetY);
    // 中心点
    const Point = new fabric.Point(offsetX, offsetY);
    const viewportTransform =
      this.canvas.viewportTransform || DEFAULT_VIEW_PORT_TRANSFORM;
    viewportTransform[0] = this.zoom;
    viewportTransform[3] = this.zoom;
    viewportTransform[4] = Point.x;
    viewportTransform[5] = Point.y;
    this.canvas.setViewportTransform(viewportTransform);
  }

  /**
   * @description 绘制区域尺寸改变监听器
   * @param {}
   * @returns {}
   */
  protected onDrawBoardResize() {
    if (!this.wrapper) return;
    this.resizeObserverIns = new ResizeObserver(
      throttle(() => {
        if (!this.wrapper) return;
        this.sceneWidth = this.wrapper.clientWidth;
        this.sceneHeight = this.wrapper.clientHeight;
        this.canvas.setWidth(this.sceneWidth);
        this.canvas.setHeight(this.sceneHeight);
        this.zoom = this.getStartZoom;
        this.sceneToCenter();
      }, 200),
    );

    this.resizeObserverIns.observe(this.wrapper);
  }

  /**
   *  ***************************************************************
   *  ************************  对外透出  ****************************
   *  ***************************************************************
   */
  public clear() {
    this.preSegInfos = new Map();
    this.clearSegmetaionMask();
    this.clearMovePreviewMask();
    this.canvas.clear();
  }

  /**
   * 获取最终的预览图片(fabric.image合并)
   */
  public async getFinalPreviewBolb(): Promise<Blob | null> {
    if (!this.pictureFabricImage || !this.segmentationMask) {
      throw new Error('请先选择要编辑的区域');
    }
    const canvas = this.createCanvasFromFabricObj([
      this.pictureFabricImage,
      this.segmentationMask.fabricObj,
    ]);
    return new Promise((resolve, reject) => {
      canvas.toBlob((blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject();
        }
      }, 'image/jpeg');
    });
  }

  /**
   * 获取最终的选中的黑白图
   */
  public async getFinallMaskBolb(): Promise<Blob | null> {
    if (!this.segmentationMask) {
      throw new Error('请先选择要编辑的区域');
    }
    const { pixelData } = this.segmentationMask;

    const finallpixelData = new Uint8ClampedArray(pixelData.length);
    for (let i = 0; i < pixelData.length; i += 4) {
      const r = pixelData[i];
      if (r > 0) {
        //不是黑色,直接设置成白色
        finallpixelData.set([255, 255, 255, 255], i);
      } else {
        finallpixelData.set([0, 0, 0, 255], i);
      }
    }
    const canvasEl = document.createElement('canvas');
    canvasEl.width = this.pictureWidth;
    canvasEl.height = this.pictureHeight;
    const imageData = new ImageData(
      finallpixelData,
      this.pictureWidth,
      this.pictureHeight,
    );
    canvasEl
      .getContext('2d', {
        colorSpace: 'srgb',
        willReadFrequently: true,
      })
      ?.putImageData(imageData, 0, 0);
    // const image = new fabric.Image(canvasEl, {
    //   selectable: false,
    // });
    // const staticCanvas = new fabric.StaticCanvas(canvasEl, {
    //   width: this.pictureWidth,
    //   height: this.pictureHeight,
    // });
    // staticCanvas.add(...[image]);
    // const canvas = staticCanvas.toCanvasElement();
    // this.canvas.add(image);
    //  canvas.toBlob()  //没有显示出白色？
    return new Promise((resolve, reject) => {
      canvasEl.toBlob((blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject();
        }
      }, 'image/jpeg');
    });
  }

  public getSegmentationMask() {
    return this.segmentationMask;
  }
  /**
   *  ***************************************************************
   *  ************************  工具函数  ****************************
   *  ***************************************************************
   */

  /**
   * @description 设置选中/1.初始化 标注工具
   * @param {}
   * @returns {}
   */
  setMarkTool(tool: EMarkTool | null) {
    this.markTool = tool;

    if (!this.markTool) {
      this.setCursor(ECursorType.POINTER);
      return;
    }
    console.log('DrawPalette--setMarkTool', tool);
    this.updateStrokeColor();
    this.updateEditorCursor();
  }

  /**
   * @description 1.1更新画笔颜色
   * @returns
   */
  updateStrokeColor() {
    if (
      this.markTool !== EMarkTool.BRUSH &&
      this.markTool !== EMarkTool.ERASER
    ) {
      this.setStrokeColor('#000000');
      return;
    }
    const { r, g, b, a } = MASK_COLOR;
    const rgbaColor = `rgba(${r}, ${g}, ${b}, ${a})`;
    this.setStrokeColor(rgbaColor);
  }

  setStrokeColor(color: string) {
    this.strokeColor = color;
  }

  /**
   * @description 1.2更新鼠标光标  自带光标 this.canvas.setCursor() 自定义光标 this.toolCursor
   * @returns
   */
  async updateEditorCursor() {
    if (!this.markTool) {
      this.setCursor(ECursorType.DEFAULT);
      return;
    }

    if (this.toolCursor) {
      this.canvas.remove(this.toolCursor);
      this.toolCursor = null;
    }

    if ([EMarkTool.AUTO_SELECT, EMarkTool.AUTO_MINUS].includes(this.markTool)) {
      const cursor =
        this.markTool === EMarkTool.AUTO_SELECT
          ? AUTO_SELECT_ACON
          : AUTO_MINUS_ICON;
      this.setCursor(`url("${cursor}"), pointer`);
      return;
    }

    if ([EMarkTool.BRUSH, EMarkTool.ERASER].includes(this.markTool)) {
      this.setCursor(ECursorType.NONE);

      const icon = await pictureLoader(
        this.markTool === EMarkTool.BRUSH ? BRUSH_ICON : ERASER_ICON,
      );
      const cursorImage = new fabric.Image(icon, {
        left: 0,
        top: 0,
        width: icon.width,
        height: icon.height,
        originX: 'center',
        originY: 'center',
        scaleX: this.strokeWidth / this.zoom / icon.width,
        scaleY: this.strokeWidth / this.zoom / icon.height,
        selectable: false,
        visible: false,
      });

      this.toolCursor = cursorImage;
      this.canvas.add(cursorImage);
    }
  }

  /**
   * @description 3.初始化  把regionIndex 转换成像素数据
   * @param { TRegionIndex, TRegionInfo[] }
   * @returns {}
   */

  async loadSegRegion() {
    const preSegInfo = PRISEGINFOS[this.version];
    const transPreSegInfo = await transPreSegInfoFormat(preSegInfo);
    this.preSegInfos.set(this.version, transPreSegInfo);
  }

  /**
   * @description 2.初始化 原始图像尺寸信息,并渲染到canvas中
   * @param {}
   * @returns {}
   */
  async initOriginPictureInfo(option: { url: string | fabric.Image }) {
    // console.log('--initOriginPictureInfo---option---:', option);
    const { url } = option;
    try {
      if (typeof url === 'string') {
        // 加载背景图像
        const pictureEl = await pictureLoader(url, { cors: false });
        const { width, height, scale } = scaleToFitMaxDimension(
          pictureEl.width,
          pictureEl.height,
        );

        this.pictureWidth = width;
        this.pictureHeight = height;
        this.pictureScale = scale;
        this.pictureFabricImage = new fabric.Image(pictureEl, {
          left: 0,
          top: 0,
          width: pictureEl.width,
          height: pictureEl.height,
          scaleX: scale,
          scaleY: scale,
        });
        this.pictureEl = pictureEl;
      } else {
        this.pictureFabricImage = url;
      }
      // 不添加到画布中来，使用img标签代替 为了兼容 EMarkTool.ERASER(橡皮擦功能，画布透明问题)
      // this.canvas.add(this.pictureFabricImage);

      this.zoom = this.getStartZoom;
      // console.log(
      //   '---------initOriginPictureInfo--this.pictureWidth--this.pictureHeight--:',
      //   this.pictureWidth,
      //   this.pictureHeight,
      //   this.zoom
      // );
      this.sceneToCenter();
      //定义一个裁剪区域，只有在此区域内的画布内容才会显示
      this.canvas.clipPath = new fabric.Rect({
        left: 0,
        top: 0,
        // width: this.pictureWidth * this.zoom,  //this.canvas.setViewportTransform()已经设置过居中缩放了
        // height: this.pictureHeight * this.zoom,
        width: this.pictureWidth,
        height: this.pictureHeight,
      });
      return true;
    } catch (error) {
      console.error(`loadPicture error: ${error}`);
      return false;
    } finally {
      this.onDrawBoardResize();
      this.loadSegRegion();
    }
  }

  clearMovePreviewMask = () => {
    if (this.movePreviewMask) {
      this.canvas.remove(this.movePreviewMask.fabricObj);
      this.movePreviewMask = null;
    }
  };

  getSegInfo(version = this.version): IPreSegInfo {
    return this.preSegInfos.get(version)!;
  }

  clearSegmetaionMask = () => {
    if (!this.segmentationMask || !this.segmentationMask.fabricObj) return;
    this.canvas.remove(this.segmentationMask.fabricObj);
    this.segmentationMask = null;
    this.emit('setSegmentationMask', null);
  };

  createCanvasFromFabricObj: (
    fabricObjs: fabric.Object[],
  ) => HTMLCanvasElement = (fabricObjs) => {
    const canvasEl = document.createElement('canvas');
    canvasEl.width = this.pictureWidth;
    canvasEl.height = this.pictureHeight;
    // fabric.StaticCanvas与fabric.Canvas的区别
    // 1.如 staticCanvas.add(new fabric.Image())画的图片在画布上是不可以进行 平移，旋转，缩放，的交互，而 fabric.Canvas可以
    const staticCanvas = new fabric.StaticCanvas(canvasEl, {
      width: this.pictureWidth,
      height: this.pictureHeight,
    });
    staticCanvas.add(...fabricObjs);
    const canvas = staticCanvas.toCanvasElement();
    return canvas;
  };

  private readonly isCoordInSegMask = (
    loc: {
      x: number;
      y: number;
    },
    segmentationMask: ISegMaskInfo2 | null,
  ): boolean => {
    // console.log('--hover--segmentationMask--:', segmentationMask);
    if (!segmentationMask || loc.x <= 0 || loc.y <= 0) return false;
    const { pixelData } = segmentationMask;
    if (!pixelData) return false; // eg: loc.y =2  //pixelData =  [第一行:[r,g,b,a...],第二行:[r,g,b,a...]]   r,g,b,a代表一个像素点
    const index = ((loc.y - 1) * this.pictureWidth + loc.x) * 4;
    if (index >= pixelData.length) return false;
    return pixelData[index] > 0; // mockData/preSegInfos.ts 中, r > 0
  };

  /**
   *
   * @param currentLoc
   * @deswcription mousemove时 获取当前位置的fabric.image
   * @returns
   */
  private async createMouseMovePreviewMask(
    currentLoc: fabric.Point,
    hoverFillColor: Record<string, number>,
  ) {
    //1.根据loc找出index,并根据 index 找出 mockData.regInfos[index].region
    const { regionIndex, regionInfos } = this.getSegInfo(this.version);
    const pixelIndex = getPixelIndexByCoord(regionIndex, currentLoc);
    if (this.movePreviewMask?.index === pixelIndex) return;
    this.clearMovePreviewMask();
    // const hoverFillColor =
    //   this.markTool === EMarkTool.AUTO_SELECT
    //     ? HOVER_MASK_COLOR
    //     : HOVER_NEGATIVE_MASK_COLOR;
    const regionInfo = regionInfos.find((item) => item.index === pixelIndex);
    if (!regionInfo) return;
    //2. 把 region(base64) 灰度图片转换成有颜色的图片，并添加到canvas中
    // 2.1 获取imageData
    const regionImage = await pictureLoader(regionInfo.region);
    const { width, height } = regionImage;
    const reginCanvas = document.createElement('canvas');
    reginCanvas.width = width;
    reginCanvas.height = height;
    const ctx = reginCanvas.getContext('2d', {
      colorSpace: 'srgb',
      willReadFrequently: true,
    });
    ctx?.drawImage(regionImage, 0, 0, width, height);
    const imageData = ctx?.getImageData(0, 0, width, height, {
      colorSpace: 'srgb',
    });
    if (!imageData) return;
    const { data } = imageData;
    //2.2 设置像素点
    const newData = new Uint8ClampedArray(data.length); // 默认值都是0,不透明度也是0
    for (let i = 0; i < data.length; i += 4) {
      if (data[i] > 0) {
        // 当前像素点的r值>0,说明当前像素点不是黑色
        const { r, g, b, a } = hoverFillColor;
        newData.set([r, g, b, a * 255], i); // i:从newData的第几项添加
      }
    }
    ctx?.putImageData(new ImageData(newData, width, height), 0, 0);
    // 每次生成的一张图，黑色区域都是透明的！
    const image = new fabric.Image(reginCanvas, {
      selectable: false,
    });

    this.movePreviewMask = {
      index: pixelIndex,
      fabricObj: image,
    };
    this.canvas.add(image);
    this.canvas.bringToFront(image);
  }

  /**
   *
   * @param currentLoc
   * @deswcription mouseup时，合并mousemove程中生成的mask
   * @returns
   */
  private async createMouseupSegmentationMask() {
    if (!this.movePreviewMask?.fabricObj) return;
    const segmentationMask = this.segmentationMask;
    const moveCanvas = this.createCanvasFromFabricObj([
      this.movePreviewMask.fabricObj,
    ]);
    const hoverCanvasImageData = moveCanvas
      .getContext('2d')
      ?.getImageData(0, 0, this.pictureWidth, this.pictureHeight);
    if (!hoverCanvasImageData) return;

    const { data } = hoverCanvasImageData;
    // if (segmentationMask) {
    // const newPixelDataArray = new Uint8ClampedArray(
    //   segmentationMask ? segmentationMask.pixelData.length : data.length
    // );
    // 不是重置，是累加
    const newPixelDataArray = new Uint8ClampedArray(
      segmentationMask ? segmentationMask.pixelData : data,
    );
    for (let i = 0; i < data.length; i += 4) {
      const [r, g, b, a] = [data[i], data[i + 1], data[i + 2], data[i + 3]]; //黑白图
      if (r > 0) {
        //不是黑色
        const pixelPoint =
          this.markTool === EMarkTool.AUTO_MINUS ||
          this.markTool === EMarkTool.ERASER
            ? [0, 0, 0, 0]
            : [r, g, b, a];
        newPixelDataArray.set(pixelPoint, i);
      }
    }
    // 2.创建 fabric.imag
    const newImageData = new ImageData(
      newPixelDataArray,
      this.pictureWidth,
      this.pictureHeight,
    );
    const mouseupCanvas = document.createElement('canvas');
    mouseupCanvas.width = this.pictureWidth;
    mouseupCanvas.height = this.pictureHeight;
    mouseupCanvas.getContext('2d')!.putImageData(newImageData, 0, 0);
    const mouseupImage = new fabric.Image(mouseupCanvas, {
      selectable: false,
    });
    segmentationMask && this.canvas.remove(segmentationMask.fabricObj);
    this.canvas.add(mouseupImage);
    this.canvas.bringToFront(mouseupImage);
    this.segmentationMask = {
      pixelData: newPixelDataArray,
      fabricObj: mouseupImage,
    };
    this.emit('setSegmentationMask', this.segmentationMask);
  }

  /**
   *  ***************************************************************
   *  ************************  事件处理操作相关  **********************
   *  ***************************************************************
   */

  private readonly addEventListener = () => {
    this.canvas.on('mouse:down', (event: fabric.IEvent) => {
      this._onMouseDown(event);
    });
    // 添加鼠标移动事件监听
    this.canvas.on('mouse:move', (event: fabric.IEvent) => {
      this._onMouseMove(event);
    });

    // 添加鼠标抬起事件监听
    this.canvas.on('mouse:up', (event: fabric.IEvent) => {
      this._onMouseUp(event);
    });
    this.wrapper?.addEventListener('mouseleave', () => {
      this.setCursor(ECursorType.DEFAULT);
      this.clearMovePreviewMask();
      if (this.toolCursor) {
        this.canvas.remove(this.toolCursor);
      }
    });
    this.wrapper?.addEventListener('mouseenter', () => {
      this.updateEditorCursor();
    });
  };

  private readonly _onMouseMove = throttle(
    async (event: fabric.IEvent): Promise<void> => {
      if (!this.markTool) return;
      const currentLoc = getLocation(event, this.canvas);
      const isOutArea = checkoutIsOutArea(
        event,
        {
          width: this.pictureWidth,
          height: this.pictureHeight,
        },
        this.canvas,
      );

      if (
        this.markTool &&
        currentLoc &&
        !isOutArea &&
        [EMarkTool.AUTO_SELECT, EMarkTool.AUTO_MINUS].includes(this.markTool)
      ) {
        //不在上次mouseup合成的整张mask有色区域内/segmentationMask不存在
        if (
          !this.isCoordInSegMask(currentLoc, this.segmentationMask) &&
          this.markTool === EMarkTool.AUTO_SELECT
        ) {
          this.createMouseMovePreviewMask(currentLoc, HOVER_MASK_COLOR);
          return;
        }

        if (this.markTool === EMarkTool.AUTO_MINUS) {
          const hoverFillColor = this.isCoordInSegMask(
            currentLoc,
            this.segmentationMask,
          )
            ? HOVER_NEGATIVE_MASK_COLOR
            : MASK_BLACK_TRANSPARENT_COLOR;
          this.createMouseMovePreviewMask(currentLoc, hoverFillColor);
          return;
        }
        return;
      }

      if (
        [EMarkTool.BRUSH, EMarkTool.ERASER].includes(this.markTool!) &&
        this.toolCursor
      ) {
        if (isOutArea) {
          this.toolCursor.set({
            visible: false,
          });
          this.canvas.sendToBack(this.toolCursor);
        } else {
          this.toolCursor.set({
            left: currentLoc!.x,
            top: currentLoc!.y,
            visible: true,
          });
          this.canvas.bringToFront(this.toolCursor);
          if (this.movePreviewMask?.pathData) {
            const nextData: TPathData[] = [
              ...this.movePreviewMask.pathData,
              ['L', currentLoc!.x, currentLoc!.y],
            ];
            if (nextData.length && nextData[0]) {
              nextData[0][0] = 'M';
            }
            this.canvas.remove(this.movePreviewMask.fabricObj);
            // @ts-ignore
            const drawAnnoBrush = new fabric.Path([...nextData], {
              strokeWidth: this.strokeWidth / this.zoom,
              stroke:
                this.markTool === EMarkTool.ERASER
                  ? 'rgba(0, 0, 0, 1)' //destination-out: 无论设置成啥颜色 drawAnnoBrush--转换成 imageData都是rgba(0,0,0,0)
                  : this.strokeColor,
              selectable: false,
              strokeLineCap: 'round', // 画笔结束笔画尾部样式（圆形）
              strokeLineJoin: 'round',
              fill: undefined,
              globalCompositeOperation:
                this.markTool === EMarkTool.ERASER
                  ? 'destination-out'
                  : 'source-over',
            });
            this.canvas.add(drawAnnoBrush);
            this.movePreviewMask = {
              index: -1,
              pathData: nextData,
              fabricObj: drawAnnoBrush,
            };
          }
        }
        return;
      }
    },
    100,
  );

  private readonly _onMouseDown = async (event: fabric.IEvent) => {
    this.isMarking = true;
    const isOutArea = checkoutIsOutArea(
      event,
      {
        width: this.pictureWidth,
        height: this.pictureHeight,
      },
      this.canvas,
    );
    if (
      !isOutArea &&
      [EMarkTool.BRUSH, EMarkTool.ERASER].includes(this.markTool!) &&
      this.toolCursor
    ) {
      const currentLoc = getLocation(event, this.canvas);
      if (!currentLoc) return;
      const pathData: TPathData[] = [['M', currentLoc.x, currentLoc.y]];
      const tempPathData: TPathData[] = [
        ...pathData,
        ['L', currentLoc.x, currentLoc.y],
      ];
      // @ts-ignore 支持 fabric.Path
      const drawAnnoBrush = new fabric.Path(tempPathData, {
        strokeWidth: this.strokeWidth / this.zoom,
        stroke: this.strokeColor,
        selectable: false,
        strokeLineCap: 'round', // 画笔结束笔画尾部样式（圆形）
        strokeLineJoin: 'round',
        fill: undefined,
      });
      if (this.markTool === EMarkTool.ERASER) {
        drawAnnoBrush.set({
          globalCompositeOperation: 'destination-out',
        });
      }
      this.canvas.add(drawAnnoBrush);
      this.canvas.bringToFront(this.toolCursor);
      this.movePreviewMask = {
        index: -1,
        fabricObj: drawAnnoBrush,
        pathData: tempPathData,
      };
    }
  };

  private readonly _onMouseUp = async (event: fabric.IEvent) => {
    if (!this.markTool || !this.isMarking) return;
    const currentLoc = getLocation(event, this.canvas);

    if (
      this.markTool &&
      currentLoc &&
      [EMarkTool.AUTO_SELECT, EMarkTool.AUTO_MINUS].includes(this.markTool) &&
      this.movePreviewMask
    ) {
      //不在上次mouseup合成的整张mask有色区域内
      if (
        (!this.isCoordInSegMask(currentLoc, this.segmentationMask) &&
          this.markTool === EMarkTool.AUTO_SELECT) ||
        this.markTool === EMarkTool.AUTO_MINUS
      ) {
        this.createMouseupSegmentationMask();
      }
    } else if (
      this.markTool &&
      currentLoc &&
      [EMarkTool.BRUSH, EMarkTool.ERASER].includes(this.markTool) &&
      this.movePreviewMask
    ) {
      const { fabricObj } = this.movePreviewMask;
      //destination-out: 无论设置成啥颜色 drawAnnoBrush--转换成 imageData都是rgba(0,0,0,0) 无法获取擦除区域的rgba
      fabricObj.globalCompositeOperation = 'source-over';
      fabricObj.stroke = this.strokeColor;
      this.createMouseupSegmentationMask();
    }

    this.clearMovePreviewMask();

    this.isMarking = false;
  };
}
